/**
 * *****************************************************************
 * @file    adt3102_timer.c
 * @author  WuHao(hwu@andartechs.com.cn)
 * @version 1.0.0
 * @date    2020-11-24
 * @brief   1.1.0, 2021/10/04, Jack, add app timer
 *                 Copyright (c) 2020, Andar Technologies Inc.
 *                           www.andartechs.com 
 *
 * *****************************************************************
 */
/*------------------------------ include -------------------------------------*/
#include "adt3102_timer.h"
#include "adt3102_type_define.h"
#include "timer_ctype_map.h"
#include "stdio.h"


/*------------------------------ variable ------------------------------------*/
volatile uint32 g_app_timerout = 0;

static ADT_APP_Timer_Typedef s_adtAppTimer[MAX_APP_TIMER_NUM];


/****************************************************************************************
*
*Function name : Timer0_Init, Timer1_Init
*Description   : Timer init,
                 50:50M high clock,if switch 125M high clock, we have to change  50 to 125
                 excute callback function when timming is up
*Paramater	   :
*        @time    set the time of the timer,the unit is us


*callback function :void Irq3_Handler()
*Return        : None
****************************************************************************************/

#ifdef TIMER_CALLBACK

timerCallback timeRoutine;
void timerCallbackTest(int32 *a )
{
    printf("aaa%d\r\n",*a);
}

static void *arg;

void timer0Handler(void)//Timer0
{
    Timer0->INTSTATUS=1;// clear timer interrupt
    if(timeRoutine)
    {
        timeRoutine(arg);
    }
}

timerCallback timer0Start(float time, timerCallback timerFunc,void *data,int32 highClock50M)
{
    uint32 reload;
    //50M   reload (us)
    reload = highClock50M ? (time*50) : (time*125);
    Timer0->RELOAD=reload;
    Timer0->CTRL=0x09;
    timeRoutine = timerFunc;
    arg = data;
    return timeRoutine;
}
#endif


/**
 * @brief   Timer initialization, 50:50M high clock,if switch 125M high clock, 
 *          we have to change 50 to 125.
 * @param   time: set the time of the timer,the unit is us.
 * @param   Timerx: include Timer0,Timer1.
 * @param   highClock50M: select high clock, include 50M and 125M.
 * @return  There is a fixed 1us for timer's function call and interruption call. for example,
 *            : when time=1   (us), the actual period is about 2us.
 *            : when time=10  (us), the actual period is about 11us.
 *            : when time=100 (us), the actual period is about 101us.
 *            : when time=1000(us), the actual period is about 1001us..
 * @note
 */
void timerInit(TimerTypeDef *Timerx, float time, int32 highClock50M)
{
    uint32 reload;
    //50M   reload (us)
    reload = highClock50M ? (time*50) : (time*125);
    Timerx->RELOAD=reload;
    Timerx->CTRL=0x09;
}


/**
 * @brief   cloes timer,clear current value.
 * @param   Timerx: include Timer0,Timer1.
 * @return  None.
 * @note
 */
void timerOff(TimerTypeDef *Timerx)
{
    Timerx->RELOAD=0;
    Timerx->CTRL=0x00;
    Timerx->VALUE=0;
}


/**
 * @brief   Timer external clock input for GPIO.
 * @param   time: set the time of the timer,the unit is us.
 * @param   Timerx: include Timer0,Timer1.
 * @param   highClock50M: select high clock, include 50M and 125M.
 * @return  None.
 * @note
 */
void timerInclock(TimerTypeDef *Timerx ,float time, int32 highClock50M)
{
    uint32 reload;
    //Timer0 External clock input GPIO is GPIO2
    //50M   reload (us)
    reload = highClock50M ? (time*50) : (time*125);
    Timerx->CTRL=0x0D;//select external input as high clock
    Timerx->RELOAD = reload;
}


/**
 * @brief   Timer external clock enable for GPIO.
 * @param   time: set the time of the timer,the unit is us.
 * @param   Timerx: include Timer0,Timer1.
 * @param   highClock50M: select high clock, include 50M and 125M.
 * @return  None.
 * @note
 */
void timerInenable(TimerTypeDef *Timerx ,float time,int32 highClock50M)
{
    uint32 reload;
    //select external GPIO as Timer enable,high level active
    //50M   reload (us)
    reload = highClock50M ? (time*50) : (time*125);
    Timerx->CTRL=0x0b;
    Timerx->RELOAD=reload;
}


/**
 * @brief   dualtimerInit.
 * @param   reloadValue: timer reload.
 * @param   clkDiv: clock is divided by clkDiv.
 *          clkDIV1   :divided by 1
 *          clkDIV16  :divided by 16
 *          clkDIV256 :divided by 256
 * @return  None.
 * @note
 */
void dualtimerInit(uint32 reloadValue, int32 clkDiv)
{
    /*RW
    [7]:timer enable
    [6]:timer mode
        0:timer is in free_runing mode
        1:timer is in periodic mode
    [5]:intterrupt enable 1:enable
    [3:2]:timerper 00: 0 stages of perscale,clock is divided by 1
                   01: 4 stages of perscale,clock is divided by 16
                   10: 8 stages of perscale,clock is divided by 256
                   11: not used
    [1]:tiemr size ,0:16-bit counter
                    1:32-bit counter
    [0]:0 wrapping mode
        1 One-shot mode
    */
    Dualtimer->TIMER2CONTROL=1<<7|1<<6|1<<5|(clkDiv<<2)|1<<1|1<<0;
    Dualtimer->TIMER2LOAD=reloadValue;

}


/**
 * @brief   APP Timer initialization, 50:50M high clock,
 *          if switch 125M high clock, we have to change 50 to 125
 * @param   Timerx: include Timer0,Timer1.
 * @param   highClock50M: set Timer clock.
 * @return  None.
 * @note
 */
void appTimerInit(TimerTypeDef *Timerx, int32 highClock50M)
{
    timerInit(Timerx,(float)1000, highClock50M);

    appTimerClean();
}


/**
 * @brief   Allocate a new APP Timer.
 * @param   None.
 * @return  id.
 * @note
 */
int8 appTimerNew(timerCb func)
{
    int id = -1;
    for(int i=0; i<MAX_APP_TIMER_NUM; i++){

        if(s_adtAppTimer[i].active == 0){

            s_adtAppTimer[i].active = 1;

            s_adtAppTimer[i].counter = 0;

            s_adtAppTimer[i].start = 0;

            s_adtAppTimer[i].timer_cb = func;

            id = s_adtAppTimer[i].id;

            break;

        }

    }

    return id;

}


/**
 * @brief   Allocate a new APP Timer.
 * @param   id: APP Timer id.
 * @param   counter: APP Timer counter.
 * @return  None.
 * @note
 */
void appTimerStart(int8 id, int32 counter)
{
    if((id < 0) || (id > MAX_APP_TIMER_NUM - 1)){
        return;
    }

    s_adtAppTimer[id].counter = counter;

    s_adtAppTimer[id].start = 1;

}

/**
 * @brief   stop a APP Timer.
 * @param   id: APP Timer id.
 * @return  None.
 * @note
 */
void appTimerStop(int8 id)
{
    if((id < 0) || (id > MAX_APP_TIMER_NUM - 1)){
        return;
    }

    s_adtAppTimer[id].start = 0;

}


/**
 * @brief   clean all APP Timer.
 * @param   None.
 * @return  None.
 * @note
 */
void appTimerClean(void)
{
    for(int i=0; i<MAX_APP_TIMER_NUM; i++){
        s_adtAppTimer[i].id         = i;
        s_adtAppTimer[i].active     = 0;
        s_adtAppTimer[i].counter    = 0;
        s_adtAppTimer[i].start      = 0;
    }
}

/****************************************************************************************
*
*Function name : app_timerAdjust
*Description   : fastforward all active APP Timer by value in million second
*Paramater		 :
*                int32 value

*Return        : None
****************************************************************************************/
void app_timerAdjust(int32 value)
{
        for(int i=0; i<MAX_APP_TIMER_NUM; i++){

            if(s_adtAppTimer[i].active == 1){
                if(s_adtAppTimer[i].counter > value){
                    s_adtAppTimer[i].counter -= value;
                }
                else
                {
                    s_adtAppTimer[i].counter = 0;
                }
            }
        }
}
/****************************************************************************************
*
*Function name : appTimerUpdate
*Description   : update all active APP Timer
*Paramater		 :
*                None
*Return        : None
****************************************************************************************/
void appTimerUpdate(void)
{
    if(g_app_timerout == 1){
        g_app_timerout = 0;

        for(int i=0; i<MAX_APP_TIMER_NUM; i++){

            if(s_adtAppTimer[i].active == 1){

                if(s_adtAppTimer[i].counter > 0){

                    s_adtAppTimer[i].counter--;

                }
                else
                {
                    if(s_adtAppTimer[i].start)
                    {
                        if(s_adtAppTimer[i].timer_cb != NULL)
                        {
                            s_adtAppTimer[i].timer_cb();
                        }
                    }
                }
            }
        }
    }
}


/**
 * @brief   check if timeout happened with one certain APP Timer.
 * @param   id: APP Timer id.
 * @return  timeout status.
 * @note
 */
int32 appTimerCheckTimeout(int8 id)
{
    if((id < 0) || (id > MAX_APP_TIMER_NUM - 1)){
        return -1;
    }

    return s_adtAppTimer[id].counter;
}
